package org.example.service.impl;

import cn.hutool.core.lang.UUID;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWTUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.example.constant.MsgConstant;
import org.example.domain.User;
import org.example.domain.vo.UserLoginRequestVO;
import org.example.mapper.UserMapper;
import org.example.pojo.LoginParams;
import org.example.service.ILoginService;
import org.example.util.EncryptionUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static org.example.constant.RedisConstant.*;

/**
 * 用户登录逻辑层
 */
@Slf4j
@Service
public class LoginServiceImpl extends ServiceImpl<UserMapper, User> implements ILoginService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 用户登录
     *
     * @param params 用户登录参数
     */
    @Override
    public UserLoginRequestVO userLogin(LoginParams params) {
        //判断验证码
        String code = params.getCode();
        if (code == null || code.equals("")) {
            return new UserLoginRequestVO("验证码不能为空", null, null);
        }
        String codeUuid = params.getCodeUuid();
        //获取缓存验证码
        String redisCode = redisTemplate.opsForValue().get(LOGIN_CODE + codeUuid);
        if (redisCode == null || redisCode.equals("")) {
            return new UserLoginRequestVO("验证码失效", null, null);
        }
        //判断验证码是否一致
        if (!code.equals(redisCode)) {
            return new UserLoginRequestVO("请输入正确的验证码", null, null);
        }
        if (StringUtils.isEmpty(params.getAccount()) || StringUtils.isEmpty(params.getPassword())) {
            return new UserLoginRequestVO("账号或密码不能为空", null, null);
        }
        //密码加密
        String md5Pwd = EncryptionUtil.md5(params.getPassword());
        //查询用户
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getAccount, params.getAccount())
                .eq(User::getPassword, md5Pwd)
                .ne(User::getIdentifying, 1)
                .ne(User::getStatus, 2)
                .eq(User::getDelFlag, 0);
        User user = this.getOne(queryWrapper);
        if (user == null) {
            return new UserLoginRequestVO("用户名或密码错误", null, null);
        }
        //用户存在，随机生成token
        String tokenUUID = UUID.randomUUID().toString();
        Map<String, Object> jwtMap = new HashMap<>();
//        jwtMap.put(TOKEN_USER_INFO, user.getId());
        jwtMap.put(TOKEN_UUID, tokenUUID);
        String token = JWTUtil.createToken(jwtMap, params.getAccount().getBytes());
        //存储在redis,30分钟过期
        redisTemplate.opsForValue().set(LOGIN_TOKEN + tokenUUID, token, TOKEN_EXPIRE_TIME, TimeUnit.MINUTES);
        //更新登录状态为已登录
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(User::getAccount, params.getAccount())
                .set(User::getStatus, 1)
                .set(User::getLoginTime, new Date())
                .setSql("login_num=login_num+1");
        this.update(updateWrapper);
        return new UserLoginRequestVO(MsgConstant.SUCCESS, token, user.getId());
    }

    /**
     * 退出登录
     *
     * @param id 用户id
     */
    @Override
    public String exitLogin(String id) {
        String msg = "";
        //更新登录状态
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(User::getId, id)
                .set(User::getStatus, 0)
                .set(User::getUpdateTime, new Date());
        boolean update = this.update(updateWrapper);
        if (update) {
            //清除token
            redisTemplate.delete(LOGIN_TOKEN + id);
            msg = MsgConstant.SUCCESS;
        } else {
            msg = MsgConstant.FAIL;
        }
        return msg;
    }
}
